﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

/* Copyright (c) 2014
 * author: Ricky Kratochwil
 * @ date: 2014-05-21
 * @ summary: Used for storing animation information only, each class in need of some graphic will need one CAnimationObj object
*/

namespace Engine
{
	class CAnimationObj
	{
		private int		m_iMaxSeq;
		private int		m_iSeq;
		private int		m_iAnimMode;
		private Bitmap	m_bmpIdle;
		private Bitmap	m_bmpAnimation;
		private bool	m_bRepeat;
		private bool	m_bRunning;			//Indicate object is currently inside animation and can not perform any other action until complete
		private int		m_iStepSize;		//Shift image by this amount per tick

		private int		m_iTickOffset;		//Only deligate next image after amount of ticks
		private int		m_iCurOffset;

		private int		m_iX;				//X position in pixel
		private int		m_iY;				//Y position in pixel

		private int		m_iID;

		public CAnimationObj(Bitmap bmpIdle, int iGridX, int iGridY)
		{
			m_bmpIdle		= bmpIdle;
			m_bmpAnimation	= null;
			m_iX			= iGridX * Const.GRID_DIM;
			m_iY			= iGridY * Const.GRID_DIM;

			m_iMaxSeq	= 0;
			m_iSeq		= 0;
			m_iAnimMode	= Const.ANIM_STATION;
			m_iStepSize	= 0;
			m_bRepeat	= false;
			m_bRunning	= false;

			m_iTickOffset = 0;
			m_iCurOffset  = 0;

			m_iID		= -1;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// SET OR REMOVE ANIMATION OBJ

		public void SetID(int iID)
		{
			m_iID = iID;
		}

		public int GetID()
		{
			return m_iID;
		}

		public void DecreaseID()
		{
			m_iID--;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// ANIMATION RELEVANT

		//Set loop
		// - Used to predetermin how many block the animation will cover (use this to resolve redraw issues)
		//@ KR / 2014.05.21
		/*public void SetLoopCount(int iValue)
		{
			m_iLoop = iValue;
		}*/

		//Set offset by which animation sprite will change
		// - Call this before starting the animation
		// - Set current Offset to maximum in order to get output at first try
		//@ KR / 2014.07.08
		public void SetTickOffset(int iValue)
		{
			m_iTickOffset = iValue;
			m_iCurOffset  = iValue;
		}

		//Set animation to start
		// - iMaxSeq musst never be 1 (no animation can be done with just 1 image)
		//@ KR / 2014.05.21
		public void SetAnimation(Bitmap bAnimation, int iMaxSeq, int iAnimMode, bool bRepeat)
		{
			m_bmpAnimation	= bAnimation;
			m_iMaxSeq		= iMaxSeq;
			m_iAnimMode		= iAnimMode;
			m_iSeq			= 0;
			m_bRepeat		= bRepeat;
			m_bRunning		= true;

			if (iMaxSeq < 3)
				m_iStepSize = 12;
			else
				m_iStepSize = Const.GRID_DIM / iMaxSeq;
		}

		//Get running state
		//@ KR / 2014.05.21
		public bool IsRunning()
		{
			return m_bRunning;
		}

		//Calles during drawing to get current image, either idle or correct animation sequence
		//@ KR / 2014.05.21
		public Bitmap GetImage()
		{
			if(m_iSeq < m_iMaxSeq)
			{
				Bitmap		bmpAnimSeq	= new Bitmap(Const.GRID_DIM, Const.GRID_DIM);
				Graphics	g			= Graphics.FromImage(bmpAnimSeq);

				//Get image from sprite sheet
				g.DrawImage(m_bmpAnimation, 
							new Rectangle(0, 0, Const.GRID_DIM, Const.GRID_DIM), 
							new Rectangle(m_iSeq*Const.GRID_DIM, 0, Const.GRID_DIM, Const.GRID_DIM), 
							GraphicsUnit.Pixel);
				g.Dispose();

				
				//Tick offset and pixel related movement
				if(m_iTickOffset > 0)
				{
					if(m_iTickOffset == m_iCurOffset)
					{
						switch(m_iAnimMode)	//Move
						{
							case Const.ANIM_RIGHT :
								m_iX += m_iStepSize;
								break;
							case Const.ANIM_LEFT :
								m_iX -= m_iStepSize;
								break;
							case Const.ANIM_UP :
								m_iY -= m_iStepSize;
								break;
							case Const.ANIM_DOWN :
								m_iY += m_iStepSize;
								break;
						}

						m_iCurOffset = 0;
						m_iSeq++;
					}
					else
						m_iCurOffset++;
				}
				else
					m_iSeq++;
					
				//If in repeat mode, the animation will restart from 0 once finished
				if((m_bRepeat /*|| m_iLoop > 1*/) && m_iSeq == m_iMaxSeq)
				{
					m_iSeq = 0;

					//Decrease loop if set (otherwise infinite loop)
					/*if(m_iLoop > 0)
						m_iLoop--;*/
				}

				if (m_iSeq == m_iMaxSeq)
					m_bRunning = false;

				return bmpAnimSeq;
			}

			return m_bmpIdle;
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// PIXEL BASED OPS

		//Return pixel coordinates for drawing
		//@ KR / 2014.05.21
		public Point GetPos()
		{
			return new Point(m_iX, m_iY);
		}

		//Set new pixel based pos using index parameters
		// - Takes current movement into account
		//@ KR / 2014.07.09
		public void SetPos(int iGridX, int iGridY)
		{
			int iXOffset = m_iX - ((m_iX/Const.GRID_DIM)*Const.GRID_DIM);
			int iYOffset = m_iY - ((m_iY/Const.GRID_DIM)*Const.GRID_DIM);

			m_iX = iGridX * Const.GRID_DIM + iXOffset;
			m_iY = iGridY * Const.GRID_DIM + iYOffset;

			//Correct displacement
			switch(m_iAnimMode)	//Move
			{
				case Const.ANIM_RIGHT :
					m_iX -= Const.GRID_DIM;
					break;
				case Const.ANIM_LEFT :
					m_iX += Const.GRID_DIM;
					break;
				case Const.ANIM_UP :
					m_iY += Const.GRID_DIM;
					break;
				case Const.ANIM_DOWN :
					m_iY -= Const.GRID_DIM;
					break;
			}
		}

//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// DESTRUCTOR

		//Dispose all Bitmaps to correctly free memory [<<IRREVERSIBLE>>]
		// - Disposes private allocated Bitmaps
		//@ KR / 2014.06.24
		public void Destroy()
		{
			if(m_bmpAnimation != null)
			{
				m_bmpAnimation.Dispose();
				m_bmpAnimation = null;
			}

			if(m_bmpIdle != null)
			{
				m_bmpIdle.Dispose();
				m_bmpIdle = null;
			}
		}
	}
}
